﻿
'function = type name(parameter_list) aliases paragraph

Imports std

Public Class [function]
    Inherits iScript
    Implements iInvokeableWithOutput

    Public Const mappingStart As Char = character.leftAngleBracket
    Public Const mappingEnd As Char = character.rightAngleBracket
    Public Const parameterStart As Char = character.leftBracket
    Public Const parameterEnd As Char = character.rightBracket

    Protected Friend Shared Function _isMeaningfulMark(ByVal c As Char) As Boolean
        Return isMappingStart(c) OrElse isMappingEnd(c) OrElse isParameterStart(c) OrElse isParameterEnd(c)
    End Function

    Private returnType As variable = Nothing
    Private _name As String = Nothing
    Private _mapping As iParametersMapping = Nothing
    Private _parameters As parameters_list = Nothing
    Private _aliases As aliases = Nothing
    Private paragraph As paragraph = Nothing

#If Not PocketPC AndAlso Not Smartphone Then
    <ThreadStatic()> Public caller As [function] = Nothing
    <ThreadStatic()> Public sentence As sentence = Nothing
#Else
    Public caller As [function] = Nothing
    Public sentence As sentence = Nothing
#End If

    Public Sub New()
        'for inline function & clone only
        Me.New(Nothing, Nothing, Nothing, Nothing, Nothing, Nothing)
    End Sub

    Protected Sub New(ByVal iname As String, ByVal imapping As iParametersMapping, _
                      ByVal iparameters As parameters_list, ByVal ialias As aliases)
        Me.New(Nothing, iname, imapping, iparameters, ialias, Nothing)
    End Sub

    Private Sub New(ByVal ireturn As variable, ByVal iname As String, _
                    ByVal imapping As iParametersMapping, _
                    ByVal iparameters As parameters_list, ByVal ialiases As aliases, ByVal ipara As paragraph)
        returnType = ireturn
        _name = iname
        _mapping = imapping
        _parameters = iparameters
        _aliases = ialiases
        paragraph = ipara
    End Sub

    Public Function name() As String
        Return _name
    End Function

    Public Function aliases() As aliases
        If _aliases Is Nothing Then
            Return aliases.empty()
        Else
            Return _aliases
        End If
    End Function

    Public Function mapping() As iParametersMapping
        If _mapping Is Nothing Then
            Return empty_parameters_mapping.empty()
        Else
            Return _mapping
        End If
    End Function

    Protected Function __parameters() As parameters_list
        If _parameters Is Nothing Then
            Return parameters_list.empty
        Else
            Return _parameters
        End If
    End Function

    Public Function callingSentence() As String
        If sentence Is Nothing Then
            Return "#CANNOT_GET_SENTENCE#"
        Else
            Return sentence.scriptAll()
        End If
    End Function

    Private Shared Sub setchild(Of T)(ByVal input As T, ByVal input2 As T, ByRef o As T, ByVal useInput2 As Boolean)
        'use copy, as only string is clonable
        copy(o, ifoper(useInput2 AndAlso input Is Nothing, input2, input))
    End Sub

    Public Function clone(Optional ByVal returnType As variable = Nothing, _
                          Optional ByVal name As String = Nothing, _
                          Optional ByVal mapping As iParametersMapping = Nothing, _
                          Optional ByVal parameters As parameters_list = Nothing, _
                          Optional ByVal aliases As aliases = Nothing, _
                          Optional ByVal paragraph As paragraph = Nothing, _
                          Optional ByVal copyReturnType As Boolean = True, _
                          Optional ByVal copyName As Boolean = True, _
                          Optional ByVal copyMapping As Boolean = True, _
                          Optional ByVal copyParameters As Boolean = True, _
                          Optional ByVal copyAliases As Boolean = True, _
                          Optional ByVal copyParagraph As Boolean = True) As [function]
        Dim rtn As [function] = Nothing
        rtn = alloc(Me)
        setchild(returnType, Me.returnType, rtn.returnType, copyReturnType)
        setchild(name, Me._name, rtn._name, copyName)
        setchild(mapping, Me._mapping, rtn._mapping, copyMapping)
        setchild(parameters, Me._parameters, rtn._parameters, copyParameters)
        setchild(aliases, Me._aliases, rtn._aliases, copyAliases)
        setchild(paragraph, Me.paragraph, rtn.paragraph, copyParagraph)

        Return rtn
    End Function

    Protected Overrides Function invokeImpl(ByVal ctx As context, _
                                            ByRef output As bare_variable) As Boolean
        assert(Not ctx Is Nothing, "ctx is nothing.")
        Dim rtn As Object = Nothing
        If returnType.invoke(rtn) Then
            ctx.insertVariable(name, New bare_variable(returnType, rtn))
            If __parameters().invoke(ctx, False) AndAlso paragraph.invoke(ctx) Then
                output = ctx.findVariable(name)
                Return True
            Else
                Return False
            End If
        Else
            Return False
        End If
    End Function

    'can add inline function directly without fake a paragraph
    Public Function invoke(ByVal ctx As context, _
                           ByRef output As bare_variable) As Boolean _
                          Implements iInvokeableWithOutput.invoke
        Return invokebase(ctx, output)
    End Function

    Private Shared Function isMappingStart(ByVal c As Char) As Boolean
        Return c = mappingStart
    End Function

    Private Shared Function isMappingEnd(ByVal c As Char) As Boolean
        Return c = mappingEnd
    End Function

    Private Shared Function isParameterStart(ByVal c As Char) As Boolean
        Return c = parameterStart
    End Function

    Private Shared Function isParameterEnd(ByVal c As Char) As Boolean
        Return c = parameterEnd
    End Function

    Protected Shared Function parseImpl(ByVal input As String, ByRef index As Int64, _
                                        ByRef output As [function]) As Boolean
        Dim returnType As variable = Nothing
        If variable.parse(input, index, returnType) Then
            Dim name As String = Nothing
            If function_name_defination.parse(input, index, name) Then
                Dim m As parameters_mapping(Of _maxInt64) = Nothing
                If token(input, index, Nothing, AddressOf isMappingStart, AddressOf [false]) AndAlso _
                   (Not parameters_mapping(Of _maxInt64).parse(input, index, m) OrElse _
                    Not token(input, index, Nothing, AddressOf isMappingEnd, AddressOf [false])) Then
                    Return False
                End If
                Dim pl As parameters_list = Nothing
                If token(input, index, Nothing, AddressOf isParameterStart, AddressOf [false]) AndAlso _
                   (Not parameters_list.parse(input, index, pl) OrElse _
                    Not token(input, index, Nothing, AddressOf isParameterEnd, AddressOf [false])) Then
                    Return False
                End If
                Dim aliases As aliases = Nothing
                If aliases.parse(input, index, aliases) Then
                    Dim para As paragraph = Nothing
                    If paragraph.parse(input, index, para) Then
                        output = New [function](returnType, name, m, pl, aliases, para)
                        Return True
                    End If
                End If
            End If
        End If
        Return False
    End Function

    Protected Overrides Sub setsource(ByVal script As String, ByVal start As Long, ByVal [end] As Long)
        setsourceImpl(returnType.scriptSource() + character.blank + name() + parameterStart + _
                      __parameters().scriptSource() + parameterEnd, start, [end])
    End Sub

    Public Shared Function parse(ByVal input As String, ByRef index As Int64, ByRef output As [function]) As Boolean
        Return parsebase(input, index, output, AddressOf parseImpl)
    End Function

    Public Overrides Function ToString() As String
        Dim rtn As String = Nothing
        rtn = name() + _
              [function].mappingStart + Convert.ToString(mapping()) + [function].mappingEnd + _
              [function].parameterStart + Convert.ToString(__parameters()) + [function].parameterEnd
        Dim aliasesStr As String = Nothing
        aliasesStr = Convert.ToString(aliases())
        If Not isemptystring(aliasesStr) Then
            rtn += character.blank + aliasesStr
        End If
        Return rtn
    End Function
End Class

Public MustInherit Class internalFunction
    Inherits [function]
    Protected MustOverride Overloads Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean

    Protected Sub New(ByVal name As String, ByVal mapping As iParametersMapping, _
                      ByVal parameters As parameters_list, ByVal aliases As aliases)
        MyBase.New(name, mapping, parameters, aliases)
        setsourceImpl("internalFunction: " + MyBase.name(), 0, 0)
    End Sub

    Protected Sub New(ByVal name As String, ByVal m As iParametersMapping, ByVal a As aliases)
        Me.New(name, m, Nothing, a)
    End Sub

    Protected Sub New(ByVal name As String, ByVal aliases As aliases)
        Me.new(name, Nothing, aliases)
    End Sub

    Protected Sub New(ByVal name As String, ByVal m As iParametersMapping)
        Me.New(name, m, Nothing)
    End Sub

    Protected Sub New(ByVal name As String)
        Me.New(name, Nothing, Nothing)
    End Sub

    Protected NotOverridable Overrides Function invokeImpl(ByVal ctx As context, _
                                                           ByRef output As bare_variable) As Boolean
        assert(Not ctx Is Nothing, "ctx is nothing.")
        If __parameters().invoke(ctx, False) Then
            Return invoke(ctx, output)
        Else
            Return False
        End If
    End Function
End Class